/* Copyright 2011 Gilberto Pacheco Gallegos.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License. You may obtain a copy of the
 * License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.  */
package net.ramptors.dominiobd.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import net.ramptors.dominiobd.client.ExcepcionDeAplicacion;
import net.ramptors.dominiobd.client.ServicioUsuarios;
import net.ramptors.dominiobd.client.entity.Grupo;
import net.ramptors.dominiobd.client.entity.Usuario;
import net.ramptors.dominiobd.client.entity.ValidadorDeUsuario;
import net.ramptors.dominiobd.client.entity.ValidadorDeUsuarioNuevo;

/**
 * @author Gilberto Pacheco Gallegos
 */
public class ServicioUsuariosImpl extends RemoteServiceServlet
    implements ServicioUsuarios {
  private static final EntityManagerFactory emf = EMF.getEmf();
  private static final ValidadorDeUsuario validador = new ValidadorDeUsuario();
  private static final ValidadorDeUsuarioNuevo validadorDeNuevo =
      new ValidadorDeUsuarioNuevo();
  @Override @SuppressWarnings("unchecked")
  public List<Usuario> buscaTodo() {
    final List<Usuario> resultado;
    final EntityManager em = emf.createEntityManager();
    try {
      final List<Usuario> lista =
          em.createQuery("SELECT o FROM Usuario o ORDER BY o.id").getResultList();
      resultado = new ArrayList<Usuario>(lista);
    } finally {
      em.close();
    }
    for (Usuario usuario : resultado) {
      usuario.setContrasena(null);
      usuario.setGrupos(new HashSet<String>(usuario.getGrupos()));
    }
    return resultado;
  }
  @Override
  public Usuario agrega(final Usuario objeto) throws ExcepcionDeAplicacion {
    validadorDeNuevo.valida(objeto);
    final EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
//      actualizaGrupos(em, objeto);
      encriptaContrasena(objeto);
      em.persist(objeto);
      em.getTransaction().commit();
      return objeto;
    } finally {
      if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
      }
      em.close();
    }
  }
  @Override
  public Usuario modifica(final Usuario objeto) throws ExcepcionDeAplicacion {
    validador.valida(objeto);
    final EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
//      actualizaGrupos(em, objeto);
      if (objeto.getContrasena() == null) {
        objeto.setContrasena(buscaContrasenaRegistrada(em, objeto.getId()));
      } else {
        encriptaContrasena(objeto);
      }
      Usuario modificado = em.merge(objeto);
      em.getTransaction().commit();
      return modificado;
    } finally {
      if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
      }
      em.close();
    }
  }
  @Override
  public void elimina(final String id) {
    final EntityManager em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
      final Usuario objeto = em.find(Usuario.class, id);
      if (objeto != null) {
        em.remove(objeto);
      }
      em.getTransaction().commit();
    } finally {
      if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
      }
      em.close();
    }
  }
  private String buscaContrasenaRegistrada(final EntityManager em, final String id)
      throws ExcepcionDeAplicacion {
    final Usuario objetoRegistrado = em.find(Usuario.class, id);
    return objetoRegistrado.getContrasena();
  }
  private Grupo buscaGrupoRegistrado(final EntityManager em, final String id)
      throws ExcepcionDeAplicacion {
    final Grupo objetoRegistrado = em.find(Grupo.class, id);
    if (objetoRegistrado == null) {
      throw new ExcepcionDeAplicacion("Grupo no registrado: " + id + ".");
    } else {
      return objetoRegistrado;
    }
  }
  private void actualizaGrupos(final EntityManager em, final Usuario objeto)
      throws ExcepcionDeAplicacion {
    final Set<String> gruposRecibidos = objeto.getGrupos();
    if (gruposRecibidos != null) {
      for (final String grupoRecibido : gruposRecibidos) {
        buscaGrupoRegistrado(em, grupoRecibido);
      }
    }
  }
  private void encriptaContrasena(final Usuario objeto) {
    final String contrasena = objeto.getContrasena();
    if (contrasena != null) {
      objeto.setContrasena(sha1(contrasena));
    }
  }
  private static String sha1(final String texto) {
    try {
      final MessageDigest md = MessageDigest.getInstance("SHA-256");
      final StringBuilder sb = new StringBuilder(64);
      for (final byte b : md.digest(texto.getBytes("UTF-8"))) {
        sb.append(String.format("%02x", (int) (b & 0xff)));
      }
      return sb.toString();
    } catch (final NoSuchAlgorithmException e) {
      throw new IllegalArgumentException(e);
    } catch (final UnsupportedEncodingException e) {
      throw new IllegalArgumentException(e);
    }
  }
}